package com.billjc.activity.taskService;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

import org.activiti.engine.RuntimeService;
import org.activiti.engine.delegate.BpmnError;
import org.activiti.engine.delegate.DelegateExecution;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.jdom.Document;
import org.jdom.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.billjc.activity.dao.PlatsysDao;
import com.billjc.activity.domain.Busdpf;
import com.billjc.activity.domain.Dyen;
import com.billjc.activity.domain.Slck;
import com.billjc.activity.entities.ECSAppInfo;
import com.billjc.activity.entities.ECSBOError;
import com.billjc.activity.entities.ECSBOErrorList;
import com.billjc.activity.entities.ECSBPMInfo;
import com.billjc.activity.entities.ECSBillingChg;
import com.billjc.activity.entities.ECSClntinfoChg;
import com.billjc.activity.entities.ECSException;
import com.billjc.activity.entities.ECSImageInfo;
import com.billjc.activity.entities.ECSLAResult;
import com.billjc.activity.entities.EFormInfo;
import com.billjc.activity.entities.Ecs;
import com.billjc.activity.prop.EcsGlobalVariable;
import com.billjc.activity.prop.EcsParams;
import com.billjc.activity.service.BusdpfService;
import com.billjc.activity.service.CreateEformService;
import com.billjc.activity.service.DyenService;
import com.billjc.activity.service.SlckService;
import com.billjc.activity.service.UpdateImageService;
import com.billjc.activity.util.EcsConstant;
import com.billjc.activity.util.Half2FullChange;
import com.billjc.activity.util.XmlUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import lombok.extern.slf4j.Slf4j;
@Service("ecsTaskService")
@Slf4j
/**
 * ecs流程任务服务类
 * @author bruce
 *
 */
public class EcsTaskService {
	@Autowired
	private RuntimeService runtimeService;
	@Autowired
	private EcsGlobalVariable global;
	@Autowired
	private PlatsysDao platsysDao;
	@Autowired
	private EcsParams ecsParams; 
	@Autowired
	private CreateEformService eformService;
	@Autowired
	private UpdateImageService imageService;
	@Autowired
	private SlckService slckService;
	@Autowired
	private DyenService dyenService;
	@Autowired
	private BusdpfService busdpfService;
	/**
	 * 初始化ecs对象
	 * @param ecsInfo
	 * @return
	 */
    public void init(DelegateExecution execution) {
    	String ecsInfo = (String) execution.getVariable("ecsInfo");
    	try {
    		JSONObject ecsObject = JSONObject.parseObject(ecsInfo);
        	String name = ecsObject.getString("name");
    		String type = ecsObject.getString("type");
    		String origin = ecsObject.getString("origin");
        	//利用jsonPath来解析json
    		JSONObject appObject = (JSONObject) JSONPath.eval(ecsObject, "$.params.param_maps[0]");
    		JSONObject clntObject = (JSONObject) JSONPath.eval(ecsObject, "$.params.param_maps[1]");
    		ECSAppInfo appInfo = JSON.toJavaObject(appObject, ECSAppInfo.class);
    		ECSClntinfoChg clntInfo = JSON.toJavaObject(clntObject, ECSClntinfoChg.class);
    		//是否为地址变更流程
    		if(global.getECSClntinfoChg().equals(appInfo.getAppType())) {
    			//将地址信息转为全角中文
    			String addr = Half2FullChange.toSBC(clntInfo.getCltAddr());
    			//把转换后的全角中文拆分成5个地址字段,以便调用Life Asia的BO
    			String[] addrArrays = Half2FullChange.splitArray(addr, 14, 10);
    			clntInfo.setCltAddr01(addrArrays[0]);
    			clntInfo.setCltAddr02(addrArrays[1]);
    			clntInfo.setCltAddr03(addrArrays[2]);
    			clntInfo.setCltAddr04(addrArrays[3]);
    			clntInfo.setCltAddr05(addrArrays[4]);
    		}
    		log.info("执行流对象获取流程实例id: {}",execution.getProcessInstanceId());
    		//初始化ECSBPMInfo对象
    		ECSBPMInfo bpmInfo = ECSBPMInfo.builder().BPDName(global.getECSBPDName()).BPDNum(execution.getProcessInstanceId()).build();
    		//初始化ECS对象
    		EFormInfo eFormInfo = EFormInfo.builder().build();
    		ECSBillingChg billingChg = ECSBillingChg.builder().build();
    		ECSLAResult lAResult = ECSLAResult.builder().build();
    		ECSImageInfo imageInfo = ECSImageInfo.builder().build();
    		ECSException exception = ECSException.builder().build();
    		Ecs ecs = Ecs.builder().name(name).type(type).lAResult(lAResult).billingChg(billingChg).exception(exception)
    				.imageInfo(imageInfo).origin(origin).appInfo(appInfo).clntInfo(clntInfo).BPMInfo(bpmInfo).eFormInfo(eFormInfo).build();
    		//将ecs对象放入环境变量
    		runtimeService.setVariable(execution.getId(), "ecs", ecs);
    		runtimeService.setVariable(execution.getId(), "globalValue", global);
    		execution.setVariable("appType", ecs.getAppInfo().getAppType());
		} catch (Exception e) {
			log.error("初始化ecs对象失败: {}",e.getMessage());
			//抛出BPMN异常,供错误边界事件捕获
			throw new BpmnError("initError");
		}
    }
    /**
     * 复效健康告知
     * @param execution
     */
    public void healthyCheck(DelegateExecution execution) {
    	//TODO
    	log.debug("----进入复效健康告知任务");
    	throw new BpmnError("serviceError");
    }
	/**
	 * 取系统时间，如果时间不在流程最小、最大时间段内，则继续等待，不调用BO
	 * @param execution
	 */
	public void getTime(DelegateExecution execution) {
		Ecs ecs= (Ecs) execution.getVariable("ecs");
		// 获取当前时间的小时
		int hour = LocalTime.now().getHour();
		if (hour > global.getECSRunMaxHour()  && hour < global.getECSRunMinHour()) {
			//直接跳到无指定的结束事件
			ecs.getLAResult().setNextStep(global.getLADayendWait());
			ecs.getLAResult().setDayendStatus(global.getLADayend());
			//ecs.getLAResult().toBuilder().nextStep(global.getLADayendWait()).dayendStatus(global.getLADayend());
		}
	}
	/**
	 * 查询LA-SLCK表，看保单是否被锁住
	 * @param execution
	 */
	public void checkSfloct(DelegateExecution execution) {
		Ecs ecs= (Ecs) execution.getVariable("ecs");
		String chdrcoy = ecs.getAppInfo().getChdrcoy();
		String chdrNum = ecs.getAppInfo().getChdrNum();
		Slck slck = slckService.getSlck(chdrcoy, chdrNum);
		log.debug("保单是否被锁住lckstsList:{} " ,slck!=null?"是":"否");
		if(slck!=null) {
			String slckResult = slck.getLcksts();
			if (global.getLAJLock().equals(slckResult) || global.getLADLock().equals(slckResult)) {
				ecs.getLAResult().setNextStep(global.getLALockWait());
			}
		}
	}
	/**
	 * 查旬LA-DYEN表看系统目前是否处于日结当中 
	 * @param execution
	 */
	public void checkDayEnd(DelegateExecution execution) {
		Ecs ecs= (Ecs) execution.getVariable("ecs");
		String nowDate = DateTimeFormatter.ofPattern(EcsConstant.PATTERN_ONE).format(LocalDate.now());
		log.debug("当前的日期： "+nowDate);
		Dyen dyen = dyenService.getDyenByBusDate(nowDate);
		log.debug("系统目前是否处于日结当中busDateList:{}" , dyen==null?"否":"是");
		if(dyen!=null) {
			String busDate = dyen.getBusdate();
			if(busDate.equals(nowDate)) {
				ecs.getLAResult().setNextStep(global.getLADayendWait());
				//ecs.getLAResult().toBuilder().nextStep(global.LADayendWait);
			}
		}
	}
	/**
	 * 取Life Asia系统日期，以便调用BO时传入正确的年、月参数
	 * @param execution
	 */
	public void getLaDate(DelegateExecution execution) {
		Ecs ecs= (Ecs) execution.getVariable("ecs");
		Busdpf busdpf = busdpfService.getBusdpf();
		log.debug("取Life Asia系统日期，以便调用BO时传入正确的年、月参数");
		String laAcctYear = "";
		String laAcctMonth = "";
		if (busdpf!=null) {
			String busD = busdpf.getBusdate();
			laAcctYear = busD.substring(0, 4);
			laAcctMonth = busD.substring(4, 6);
		}else {
			// 如果Life Asia数据库中没有系统日期,则取服务器年月
			LocalDate now = LocalDate.now();
			laAcctYear = String.valueOf(now.getYear());
			laAcctMonth = String.valueOf(now.getMonthValue());
		} 
		ecs.getLAResult().setLAAcctMonth(laAcctMonth);
		ecs.getLAResult().setLAAcctYear(laAcctYear);
		//ecs.getLAResult().toBuilder().lAAcctMonth(laAcctMonth).lAAcctYear(laAcctYear);
	}
	/**
	 * call 客户资料变更bo
	 * @param execution
	 */
	public void startCallBo(DelegateExecution execution) {
		Ecs ecs= (Ecs) execution.getVariable("ecs");
		callClntinfo(ecs);
	}
	/**
	 * 设置状态
	 * @param execution
	 */
	public void setNextStep(DelegateExecution execution) {
		Ecs ecs= (Ecs) execution.getVariable("ecs");
		//判断日结
		if(StringUtils.equals(ecs.getLAResult().getDayendStatus(), global.getLADayend())) {
			ecs.getLAResult().setNextStep(global.getLADayendWait());
		}else {
			//非日结中
	        //如果SLCK是J锁或者D锁，则下一步等待锁结束  
			if(StringUtils.equals(global.getLAJLock(), ecs.getLAResult().getSlckStatus()) || StringUtils.equals(global.getLADLock(), ecs.getLAResult().getSlckStatus())) {
				ecs.getLAResult().setNextStep(global.getLALockWait());
			}
		    //如果SLCK是A锁或者E锁，则下一步走更新外网状态，但是受理状态为转人工处理
			if(StringUtils.equals(global.getLAALock(), ecs.getLAResult().getSlckStatus()) || StringUtils.equals(global.getLAELock(), ecs.getLAResult().getSlckStatus())) {
				ecs.getLAResult().setNextStep(global.getLAComplete());
				ecs.getAppInfo().setAppStatus(global.getAppFollowup());
			}
			//如果没有SLCK，则下一步走更新外网状态，并将BO返回的保单状态赋给受理状态。
	        //但是如果BO返回错误，则受理状态为转人工处理
			if(StringUtils.isEmpty(ecs.getLAResult().getSlckStatus())) {
				ecs.getLAResult().setNextStep(global.getLAComplete());
				if(!StringUtils.equals(ecs.getLAResult().getBOStatus(), global.getLABOSuccess())) {
					ecs.getAppInfo().setAppStatus(global.getAppFollowup());
				}
			}
		}
		execution.setVariable("nextStep", ecs.getLAResult().getNextStep()==null?"":ecs.getLAResult().getNextStep());
	}
	/**
	 * 更新外网状态
	 * @param execution
	 */
	public void updateWebSite(DelegateExecution execution) {
		log.debug("进入更新外网任务");
		try {
			Ecs ecs= (Ecs) execution.getVariable("ecs");
			String appStatus = ecs.getAppInfo().getAppStatus();
			String appNum = ecs.getAppInfo().getAppNum();
			int result = platsysDao.updateAppStatus(appStatus, appNum);
			if(result>0) {
				log.debug("更新外网状态成功");
			}
		} catch (Exception e) {
			log.error("更新外网状态出现异常");
			throw new BpmnError("updateError");
		}
		
	}
	/**
	 * 请求eform
	 * @param execution
	 */
	public void createEform(DelegateExecution execution) {
		log.debug("请求eform");
		Ecs ecs= (Ecs) execution.getVariable("ecs");
		eformService.executeService(ecs);
	}
	/**
	 * 上传影像
	 * @param execution
	 */
	public void uploadFile(DelegateExecution execution) {
		log.debug("上传影像");
		Ecs ecs= (Ecs) execution.getVariable("ecs");
		imageService.uploadFile(ecs);
	}
	/**
	/**
	 * 组装call bo 数据映射
	 * @param ecs
	 * @return
	 */
	private Map<String, Object> builtCallBoMap(Ecs ecs){
		Map<String, Object> result = Maps.newHashMap();
		result.put(EcsConstant.ORDERNUM, ecs.getAppInfo().getAppNum());
		result.put(EcsConstant.CSNUM, ecs.getBPMInfo().getBPDName());
		result.put(EcsConstant.CSCODE, ecsParams.getProcessType());
		result.put(EcsConstant.CLNTNUM, ecs.getAppInfo().getClntNum());
		result.put(EcsConstant.CHDRNUM, ecs.getAppInfo().getChdrNum());
		result.put(EcsConstant.RMBLPHONE, ecs.getClntInfo().getRmblPhone());
		List<String> phoneList = Lists.newArrayList();
		phoneList.add(ecs.getClntInfo().getCltPhone01());
		phoneList.add(ecs.getClntInfo().getCltPhone02());
		result.put(EcsConstant.CLTPHONE, phoneList);
		result.put(EcsConstant.RINTERNET, ecs.getClntInfo().getRinternet());
		List<String> addrList = Lists.newArrayList();
		addrList.add(ecs.getClntInfo().getCltAddr01());
		addrList.add(ecs.getClntInfo().getCltAddr02());
		addrList.add(ecs.getClntInfo().getCltAddr03());
		addrList.add(ecs.getClntInfo().getCltAddr04());
		addrList.add(ecs.getClntInfo().getCltAddr05());
		result.put(EcsConstant.CLTADDR, addrList);
		result.put(EcsConstant.CLTPCODE, ecs.getClntInfo().getCltPCode());
		result.put(EcsConstant.DIRMAIL, ecs.getClntInfo().getSmsSel());
		result.put(EcsConstant.COMPANY, ecs.getAppInfo().getChdrcoy());
		result.put(EcsConstant.BRANCH, ecs.getAppInfo().getBranch());
		result.put(EcsConstant.LANGUAGE, global.getAppLanguage());
		result.put(EcsConstant.ACCTYR, ecs.getLAResult().getLAAcctYear());
		result.put(EcsConstant.ACCTMN, ecs.getLAResult().getLAAcctMonth());
		result.put(EcsConstant.USRPRF, "");
		result.put(EcsConstant.WKSID, "");
		return result;
	}
	/**
	 * call 客户资料变更bo
	 * @param ecs
	 * @return
	 * @throws Exception 
	 */
    public String callClntinfo(Ecs ecs){
    	//组装call bo map数据
    	Map<String, Object> reflectMap = builtCallBoMap(ecs);
    	//创建CXF动态客户端
    	JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
    	Client client = dcf.createClient(ecsParams.getServiceUrl());
    	//通过反射设置webService请求参数
    	Object targetRequest = reflectJavaBean(reflectMap);
    	try {
    		//执行请求
    		Object[] responseArr = client.invoke("callBOSUCSCLT", targetRequest);
    		Object respnese = responseArr[0];
    		handleResponse(respnese, ecs);
		} catch (Exception e) {
			e.printStackTrace();
		}
    	return null;
    }
    /**
     * 处理Bo返回信息
     * @param respnese
     * @param ecs
     */
    private void handleResponse(Object respnese,Ecs ecs) {
    	try {
    		Object responseBean = respnese.getClass().getMethod("getBOSUCSCLTResponseBean").invoke(respnese);
    		//获取callbo返回的xml报文
    		String resultXml = (String) responseBean.getClass().getMethod("getMResult").invoke(responseBean);
    		//获取错误信息
    		//String errorMsg = (String) responseBean.getClass().getMethod("getERRORMSG").invoke(responseBean);
    		String dystuz = (String) responseBean.getClass().getMethod("getDYSTUZ").invoke(responseBean);
    		if(StringUtils.isNotEmpty(dystuz)) {
    			String slstuz = (String) responseBean.getClass().getMethod("getSLSTUZ").invoke(responseBean);
        		String statCode = (String) responseBean.getClass().getMethod("getSTATCODE").invoke(responseBean);
        		String statuz = (String) responseBean.getClass().getMethod("getSTATUZ").invoke(responseBean);
    			ecs.getLAResult().setDayendStatus(dystuz);
    			ecs.getLAResult().setSlckStatus(slstuz);
    			ecs.getLAResult().setChdrStatus(statCode);
    			ecs.getLAResult().setBOStatus(statuz);
    			if(global.getLABOSuccess().equals(statuz)) {
    				ecs.getAppInfo().setAppStatus(global.getAppComplete());
    			}
    		}
    		if(StringUtils.isNotEmpty(resultXml)) {
    			Document document = XmlUtil.builtDocument(resultXml);
    			Element root = document.getRootElement();
    			Element errorElement = XmlUtil.getSingleElement(document.getRootElement(), "//structParm[@name='WSAA-RSPDTA' and @passDirection='out']/struct[@name='LEADER-HEADER']/stringParm[@name='ERRLVL']");
    			String errorLevel = errorElement.getText();
    			if(!StringUtils.equals("0", errorLevel)) {
    				List<Element> errorListElement = XmlUtil.getElementsByPath(root, "//structParm[@name='WSAA-RSPDTA' and @passDirection='out']/struct[@name='BOVERRREC']/struct[@name='MESSAGE-DATA-O']/arrayOfStructParm[@name='BOVERR-ERRORS']//struct[@name='BOVERR-ERRORS']");
    				for(Element element : errorListElement) {
    					Element filedElement = XmlUtil.getSingleElement(element, "//stringParm[@name='BOVERR-FIELD']");
    					Element erorElement = XmlUtil.getSingleElement(element, "//stringParm[@name='BOVERR-EROR']");
    					Element descElement = XmlUtil.getSingleElement(element, "//stringParm[@name='BOVERR-DESC']");
    					String filed = filedElement.getText();
    					String eror = erorElement.getText();
    					String desc = descElement.getText();
    					if(StringUtils.isNotEmpty(filed) || StringUtils.isNotEmpty(eror) || StringUtils.isNotEmpty(desc)) {
    						ECSBOErrorList errorList = ECSBOErrorList.builder().filed(filed).error(eror).desc(desc).build();
    						ECSBOError ecsboError = ECSBOError.builder().build();
    						ecsboError.getErrorList().add(errorList);
    						ecs.getLAResult().setBOError(ecsboError);
    					}
    				}
    			}else {
    				log.error("bo 未返回相关bo文件,call客户资料变更bo异常");
    				throw new BpmnError("callboError");
    			}
    		}
		} catch (Exception e) {
			throw new BpmnError("callboError");
		}
    }
    /**
     * 反射为对象设值
     * @param reflectMap
     * @return
     */
	private Object reflectJavaBean(Map<String, Object> reflectMap) {
		Object request = null;
		Object targetRequest = null;
		try {
			request = Thread.currentThread().getContextClassLoader().loadClass("com.siebre.BOSUCSCLTRequestBean")
					.newInstance();
			targetRequest = Thread.currentThread().getContextClassLoader().loadClass("com.siebre.CallBOSUCSCLTRequest")
					.newInstance();
			for (Map.Entry<String, Object> entry : reflectMap.entrySet()) {
				String key = entry.getKey();
				Object value = entry.getValue();
				if (EcsConstant.CLTPHONE.equals(key) || EcsConstant.CLTADDR.equals(key)) {
					Field targetField = request.getClass().getDeclaredField(key.toLowerCase());
					targetField.setAccessible(true);
					targetField.set(request, value);
				} else {
					Method setMethod = request.getClass().getMethod("set" + key, String.class);
					setMethod.invoke(request, value);
				}
			}
			Method targetMethod = targetRequest.getClass().getMethod("setBOSUCSCLTRequestBean", request.getClass());
			targetMethod.invoke(targetRequest, request);
		} catch (Exception e) {
		}
		return targetRequest;
    }
}
